package logs

import (
	"io"
	"log"
	"os"
	"sync"
)

var lock sync.Mutex
var (
	_all   *log.Logger // 记录所有日志
	_debug *log.Logger // 调式信息
	_info  *log.Logger // 正常信息
	_warn  *log.Logger // 警告信息
	_error *log.Logger // 错误信息
)

type LogLevel int

const (
	LEVEL_ERROR LogLevel = iota
	LEVEL_WARN
	LEVEL_INFO
	LEVEL_DEBUG
)

var (
	level    = LEVEL_INFO
	initd    = false
	_setting = Setting{
		FilePrefix:   "wui",
		SplitFile:    false,
		WriteConsole: true,
		WriteFile:    true,
	}
)
var (
	error = "ERROR"
	warn  = "WARN"
	info  = "INFO"
	debug = "DEBUG"
)

func SetSetting(setting Setting) {
	lock.Lock()
	defer lock.Unlock()
	if !initd {
		_setting = setting
		initd = true
	}
	if _setting.SplitFile {
		debugFile, err := os.OpenFile(_setting.FilePrefix+"_debug.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		infoFile, err := os.OpenFile(_setting.FilePrefix+"_info.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		warnFile, err := os.OpenFile(_setting.FilePrefix+"_warn.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		errorFile, err := os.OpenFile(_setting.FilePrefix+"_error.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalln("Failed to open error logs file:", err)
		}
		if _setting.WriteConsole && _setting.WriteFile {
			_error = log.New(io.MultiWriter(errorFile, os.Stderr), "", log.Ldate|log.Ltime)
			_warn = log.New(io.MultiWriter(warnFile, os.Stdout), "", log.Ldate|log.Ltime)
			_info = log.New(io.MultiWriter(infoFile, os.Stdout), "", log.Ldate|log.Ltime)
			_debug = log.New(io.MultiWriter(debugFile, os.Stdout), "", log.Ldate|log.Ltime)
		} else if _setting.WriteConsole {
			_error = log.New(io.MultiWriter(os.Stderr), "", log.Ldate|log.Ltime)
			_warn = log.New(io.MultiWriter(os.Stdout), "", log.Ldate|log.Ltime)
			_info = log.New(io.MultiWriter(os.Stdout), "", log.Ldate|log.Ltime)
			_debug = log.New(io.MultiWriter(os.Stdout), "", log.Ldate|log.Ltime)
		} else {
			_error = log.New(io.MultiWriter(errorFile), "", log.Ldate|log.Ltime)
			_warn = log.New(io.MultiWriter(warnFile), "", log.Ldate|log.Ltime)
			_info = log.New(io.MultiWriter(infoFile), "", log.Ldate|log.Ltime)
			_debug = log.New(io.MultiWriter(debugFile), "", log.Ldate|log.Ltime)
		}
	} else {
		allFile, err := os.OpenFile(_setting.FilePrefix+"_all.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			log.Fatalln("Failed to open error logs file:", err)
		}
		if _setting.WriteConsole && _setting.WriteFile {
			_all = log.New(io.MultiWriter(allFile, os.Stdout), "", log.Ldate|log.Ltime)
		} else if _setting.WriteConsole {
			_all = log.New(io.MultiWriter(os.Stdout), "", log.Ldate|log.Ltime)
		} else {
			_all = log.New(io.MultiWriter(allFile), "", log.Ldate|log.Ltime)
		}
	}
}

type Setting struct {
	FilePrefix   string
	SplitFile    bool
	WriteConsole bool
	WriteFile    bool
}

func DefaultSetting() Setting {
	return _setting
}

func __initd() {
	if !initd {
		SetSetting(_setting)
	}
}
func _printf(log *log.Logger, format, prefix string, v ...interface{}) {
	n := append([]interface{}{prefix}, v...)
	log.Printf(format, n...)
}

func _println(log *log.Logger, prefix string, v ...interface{}) {
	n := append([]interface{}{prefix}, v...)
	log.Println(n...)
}

func Level(l LogLevel) {
	lock.Lock()
	defer lock.Unlock()
	level = l
}

func Error(v ...interface{}) {
	if level >= LEVEL_ERROR {
		__initd()
		if _setting.SplitFile {
			_println(_error, error, v...)
		} else {
			_println(_all, error, v...)
		}
	}
}

func Warn(v ...interface{}) {
	if level >= LEVEL_WARN {
		__initd()
		if _setting.SplitFile {
			_println(_warn, warn, v...)
		} else {
			_println(_all, warn, v...)
		}
	}
}

func Info(v ...interface{}) {
	if level >= LEVEL_INFO {
		__initd()
		if _setting.SplitFile {
			_println(_info, info, v...)
		} else {
			_println(_all, info, v...)
		}
	}
}

func Infof(format string, v ...interface{}) {
	if level >= LEVEL_INFO {
		__initd()
		if _setting.SplitFile {
			_printf(_info, format, info, v...)
		} else {
			_printf(_all, format, info, v...)
		}
	}
}

func Debug(v ...interface{}) {
	if level >= LEVEL_DEBUG {
		__initd()
		if _setting.SplitFile {
			_println(_debug, debug, v...)
		} else {
			_println(_all, debug, v...)
		}
	}
}
